package top.codedance.iotp.server.net;

import com.alibaba.fastjson.JSONObject;
import top.codedance.iotp.server.ServerApplication;
import top.codedance.iotp.server.net.handle.configuration.HttpRouteConfig;
import top.codedance.iotp.server.net.handle.subhandle.controller.Controller;
import io.undertow.Undertow;
import io.undertow.UndertowOptions;
import io.undertow.server.RoutingHandler;
import io.undertow.util.Headers;
import org.apache.log4j.Logger;
import org.xnio.Options;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Set;

public class AdvancedHttpServer implements Server {
    private Logger logger = ServerApplication.getLogger(AdvancedHttpServer.class);
    private int port;
    private String ip;

    public AdvancedHttpServer(String ip, int port) {
        this.port = port;
        this.ip = ip;
    }

    @Override
    public void run() {
        AbstractHttpServer.httpRoutes.putAll(HttpRouteConfig.getConfig());
        final RoutingHandler handler = new RoutingHandler();
        Set<Map.Entry<String, Controller>> entries = AbstractHttpServer.httpRoutes.entrySet();
        for(Map.Entry<String, Controller> entity : entries) {
            handler.post(entity.getKey(), exchange -> {
                exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json; charset=UTF-8");
                exchange.getRequestReceiver().receiveFullBytes(
                        (exchange1, message) -> {
                            String content = entity.getValue().doHandler(message);
                            JSONObject tmpJo = JSONObject.parseObject(content);
                            if(tmpJo.containsKey("message")){
                                if(tmpJo.get("message") == null || tmpJo.getString("message").isEmpty()){
                                    tmpJo.remove("message");
                                }
                            }
                            if(tmpJo.containsKey("data")){
                                if(tmpJo.get("data") == null || tmpJo.getString("data").isEmpty()){
                                    tmpJo.remove("data");
                                }
                            }
                            exchange.getResponseSender().send(tmpJo.toJSONString(), StandardCharsets.UTF_8);
                        },
                        (exchange12, exception) -> {
                            exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json; charset=UTF-8");
                            JSONObject result = new JSONObject();
                            result.put("status", 500);
                            result.put("message", exception.getMessage());
                            exchange.getResponseSender().send(result.toJSONString(), StandardCharsets.UTF_8);
                        }
                );
            });
        }

        handler.setFallbackHandler(exchange -> {
            exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json; charset=UTF-8");
            JSONObject result = new JSONObject();
            result.put("status", 404);
            result.put("message", "Not find page.");
            exchange.getResponseSender().send(result.toJSONString(), StandardCharsets.UTF_8);
        });

        Undertow server = Undertow.builder()
                .addHttpListener(this.port, this.ip)
                .setHandler(handler)
                .setIoThreads(ServerApplication.ioThreads)
                .setWorkerThreads(ServerApplication.workerThreads)
                .setBufferSize(1024)
                .setDirectBuffers(true)
                .setServerOption(UndertowOptions.MAX_ENTITY_SIZE, (long)1024 * 1024 * 1024)
                .build();
        server.start();
        ServerApplication.syslogInfo(String.format("Advanced httpd server bind port %s success", port));

        Object lock = new Object();
        synchronized (lock) {
            try {
                lock.wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                ServerApplication.syslogInfo("Advanced httpd server interrupted while waiting for stop signal");
            }
        }

        server.stop();
    }
}
